/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = frhex_dump.c                                                  */
/*  NOTE      =                                                               */
/*  DATE      = 2014/12/01 by geyh                                            */
/******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <ctype.h>

#include "frmem.h"

#define DUMP_PREFIX_NONE                0
#define DUMP_PREFIX_OFFSET              1
#define DUMP_PREFIX_ADDRESS             2

#define FR_HEX_DUMP_SIZE_MIN            1024
#define FR_HEX_DUMP_SIZE_LINE           128


static char hex_asc[] = "0123456789abcdef";
#define hex_asc_lo(x)   hex_asc[((x) & 0x0f)]
#define hex_asc_hi(x)   hex_asc[((x) & 0xf0) >> 4]

/*******************************************************************************
*  FUNC     :  将2进制数据转换为可见的内容(16个字节)
*           :  例（p_buf="\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b
*           :     \x4c\x4d\x4e\x4f"
*           :   输出为40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
*           :   当输入二进制数据超出assic表范围时,输出为“."
*  ARGS     :  p_buf                (2进制数据)
*           :  *p_i_len                  (要转化的数据的长度)
*           :  i_rowsize            (每行要输出的字节数)
*           :  i_groupsize          (每个单元所占的字节数)
*           :  pp_linebuf           (输出)
*           :  i_ascii              (是否是assic)  0或1
*  RTN      :
*  NOTE     :  pp_linebuf  内存释放
*******************************************************************************/

void static __hex_dump_to_buffer(const void *p_buf, int *p_i_len, int i_rowsize,
                        int i_groupsize, char **pp_linebuf,int i_ascii)
{
    const unsigned char *p_ptr = (const unsigned char *)p_buf;
    unsigned char ch;
    char *p_linebuf = NULL;
    int i_loop1, i_used = 0;
    int i_ascii_column;
    int i_size = FR_HEX_DUMP_SIZE_LINE;
    int i_line_size = 0;

    if (i_rowsize != 16 && i_rowsize != 32)
        i_rowsize = 16;

    if (!*p_i_len)
        goto nil;
    if (*p_i_len > i_rowsize)              /* limit to one line at a time */
    {
        i_line_size = i_rowsize;
        *p_i_len -= i_rowsize;
    }
    else
    {
        i_line_size = *p_i_len;
        *p_i_len = 0;
    }

    if ((i_line_size % i_groupsize) != 0)     /* no mixed size output */
        i_groupsize = 1;

    p_linebuf = (char *)frmalloc(i_size);
    if(p_linebuf == NULL)
        return;

    //转换
    switch (i_groupsize)
    {
    //long long
        case 8:
        {
            const unsigned long long *ptr8 = (const unsigned long long *)p_buf;
            int i_ngroups = i_line_size / i_groupsize;

            for (i_loop1 = 0; i_loop1 < i_ngroups; i_loop1++)
                i_used += snprintf(p_linebuf + i_used, i_size - i_used,
                    "%s%16.16llx", i_loop1 ? " " : "",
                    (unsigned long long)*(ptr8 + i_loop1));
            i_ascii_column = 17 * i_ngroups + 2;
            break;
        }
        //long
        case 4:
        {
            const long *ptr4 = (const long *)p_buf;
            int i_ngroups = i_line_size / i_groupsize;

            for (i_loop1 = 0; i_loop1 < i_ngroups; i_loop1++)
                i_used += snprintf(p_linebuf + i_used, i_size - i_used,
                        "%s%8.8lx", i_loop1 ? " " : "", *(ptr4 + i_loop1));
            i_ascii_column = 9 * i_ngroups + 2;
            break;
        }
        //int
        case 2:
        {
            const unsigned int *ptr2 = (const unsigned int *)p_buf;
            int i_ngroups = i_line_size / i_groupsize;

            for (i_loop1 = 0; i_loop1 < i_ngroups; i_loop1++)
                i_used += snprintf(p_linebuf + i_used, i_size - i_used,
                        "%s%4.4x", i_loop1 ? " " : "", *(ptr2 + i_loop1));
            i_ascii_column = 5 * i_ngroups + 2;
            break;
        }
        //char
        default:
        {
            for (i_loop1 = 0; (i_loop1 < i_line_size) && (i_used + 3) <= i_size; i_loop1++) {
                ch = p_ptr[i_loop1];
                p_linebuf[i_used++] = hex_asc_hi(ch);
                p_linebuf[i_used++] = hex_asc_lo(ch);
                p_linebuf[i_used++] = ' ';
            }
            if (i_loop1)
                i_used--;

            i_ascii_column = 3 * i_rowsize + 2;
            break;
        }
    }
    if (!i_ascii)
            goto nil;

    while (i_used < (i_size - 1) && i_used < (i_ascii_column - 1))
            p_linebuf[i_used++] = ' ';
    for (i_loop1 = 0; (i_loop1 < i_line_size) && (i_used + 2) < i_size; i_loop1++)
            p_linebuf[i_used++] = (isascii(p_ptr[i_loop1]) && isprint(p_ptr[i_loop1])) ? p_ptr[i_loop1]
                            : '.';
nil:
        p_linebuf[i_used++] = '\0';
        *pp_linebuf = p_linebuf;
}




int frhex_dump_to_buffer(const void *p_buf, int i_len,char **pp_outbuf)
{
    const void *p_buf_in = NULL;
    int i_ascii = 1;
    int i_rowsize = 16;
    int i_groupsize = 1;
    int i_size = FR_HEX_DUMP_SIZE_MIN, i_used = 0;
    char *p_outbuf = NULL;
    char *p_line_outbuf = NULL;
    char *p_tmp = NULL;

    if( p_buf == NULL|| i_len <= 0 || pp_outbuf == NULL )
        return 1;

    p_outbuf = (char *)frmalloc(i_size);
    if(p_outbuf == NULL)
        return 1;

    memset(p_outbuf,0x00,i_size);

    p_buf_in = p_buf;

    while(i_len)
    {
        //将单行的数据转化
        __hex_dump_to_buffer(p_buf_in,&i_len,i_rowsize,i_groupsize,&p_line_outbuf,i_ascii);

        //如果p_outbuf内存足够  strlen(p_line_outbuf) + 换行 + "\0"
        if(i_used + strlen(p_line_outbuf) + 2 < i_size)
        {
            snprintf(p_outbuf + i_used,i_size,"%s%s",p_line_outbuf,"\n");
            i_used = i_used + 1 + strlen(p_line_outbuf);
            frfree(p_line_outbuf);
        }
        //内存不足时申请内存
        else
        {
            i_size += FR_HEX_DUMP_SIZE_MIN;
            p_tmp = (char *)frmalloc(i_size);
            if(p_tmp == NULL)
            {
                frfree(p_outbuf);
                frfree(p_line_outbuf);
                return 1;
            }

            snprintf(p_tmp,i_size,"%s",p_outbuf);

            frfree(p_outbuf);
            p_outbuf = p_tmp;
            //继续读入内容
            snprintf(p_outbuf + i_used,i_size,"%s%s",p_line_outbuf,"\n");

            // 换行 + strlen(p_line_outbuf)
            i_used = i_used + 1 + strlen(p_line_outbuf);
            frfree(p_line_outbuf);
        }
        //指针后移
        p_buf_in = (unsigned char*)p_buf_in + 16;

    }

    *pp_outbuf = p_outbuf;
    return 0;
}
